package com.qijian.production.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qijian.common.core.domain.entity.SysUser;
import com.qijian.common.enums.FlowableKeyEnum;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.DateUtils;
import com.qijian.common.utils.ObjectUtils;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.maindata.domain.*;
import com.qijian.production.domain.PointOrder;
import com.qijian.production.domain.PointOrderItem;
import com.qijian.production.domain.PointOrderItemDetail;
import com.qijian.production.domain.query.PointOrderQuery;
import com.qijian.production.domain.vo.PointOrderVo;
import com.qijian.production.mapper.PointOrderMapper;
import com.qijian.production.service.IPointOrderItemDetailService;
import com.qijian.production.service.IPointOrderItemService;
import com.qijian.production.service.IPointOrderService;
import com.qijian.tool.domain.Msg;
import com.qijian.tool.service.IMsgService;
import com.qijian.tool.service.IStorageService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 非标准定额申请单Service业务层处理
 *
 * @author qijian
 * @date 2023-12-06
 */
@Service
@RequiredArgsConstructor
public class PointOrderServiceImpl extends ServiceImpl<PointOrderMapper, PointOrder> implements IPointOrderService {

    private final PointOrderMapper pointOrderMapper;

    private final IPointOrderItemService pointOrderItemService;

    private final IPointOrderItemDetailService pointOrderItemDetailService;

    private final IStorageService storageService;

    private final IMsgService msgService;


    @Override
    @Transactional(rollbackFor = {Exception.class, ServiceException.class})
    public String saveOrUpdateOrder(PointOrderVo pointOrderVo) {
        //参数校验
        validate(pointOrderVo);

        if (pointOrderVo.getId() == null) {
            //新增
            pointOrderVo.setNumber(IdUtils.getNumber("FBZDE-", pointOrderMapper.countCurrentDateWithDel() + 1));
            this.save(pointOrderVo);
        } else {
            //根据id修改
            this.updateById(pointOrderVo);
        }
        //清除明细及派工人员
        pointOrderItemService.remove(new LambdaQueryWrapper<PointOrderItem>().eq(PointOrderItem::getMainId, pointOrderVo.getId()));
        pointOrderItemDetailService.remove(new LambdaQueryWrapper<PointOrderItemDetail>().eq(PointOrderItemDetail::getMainId, pointOrderVo.getId()));

        //保存明细及派工人员
        List<PointOrderItem> items = new ArrayList<>();
        List<PointOrderItemDetail> details = new ArrayList<>();
        pointOrderVo.getItems().forEach(i -> {
            details.addAll(i.initDetailMain(pointOrderVo.getId()));
            items.add(i);
        });
        pointOrderItemService.saveBatch(items);
        pointOrderItemDetailService.saveBatch(details);
        //对上传文件操作
        if (CollUtil.isNotEmpty(pointOrderVo.getFiles())) {
            pointOrderVo.getFiles().forEach(file -> {
                file.setClassTable(PointOrder.class.getSimpleName());
                file.setClassId(pointOrderVo.getId());
            });
            storageService.updateBatchById(pointOrderVo.getFiles());
        }
        return pointOrderVo.getId().toString();
    }

    @Override
    public PointOrderVo getVoById(Long id) {
        PointOrderVo pointOrderVo = baseMapper.selectVoById(id);
//        if (pointOrderVo != null && CollectionUtils.isNotEmpty(pointOrderVo.getDetails())) {
//            pointOrderVo.setDetails(Arrays.asList(pointOrderVo.getDetails().get(0)));
//        }
        return pointOrderVo;
    }

    @Override
    public Page<PointOrderVo> pageVo(Page<PointOrderVo> page, QueryWrapper<PointOrderQuery> queryWrapper) {
        return baseMapper.selectVo(page, queryWrapper);
    }

    @Override
    public List<PointOrderVo> selectVoByCondition(Wrapper<PointOrderQuery> queryWrapper) {
        return baseMapper.selectVoByCondition(queryWrapper);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createProcessOrder(Long mainId, String title, String userName, String createTime, String oUserId, String processInstanceId) {
        PointOrderVo pointOrderVo = this.getVoById(mainId);

        check(pointOrderVo);

        //按开工令生成工单
        List<ProcessOrderUsers> orderUsers = new ArrayList<>();
        List<ProcessOrder> orders = new ArrayList<>();

        pointOrderVo.getItems().forEach(item -> {
            //根据开工令生成工单数据
            ProcessOrder processOrder = new ProcessOrder();
            processOrder.setProjectId(item.getProjectId());
            processOrder.setWorkId(IdUtils.singletonSnowId());
            processOrder.setProcessName(item.getProcessName());
            processOrder.setProcessTypeName(item.getProcessTypeName());
            processOrder.setItemName(item.getItemName());
            processOrder.setStatus(0);//已完成工单
            processOrder.setDispatchTime(DateUtils.getNowDate());
            String workCodePrefix = String.format("%s(%s#)-", item.getProjectNo(), (item.getMachineNo() == null ? "" : item.getMachineNo()));
            processOrder.setWorkCode("Po-" + workCodePrefix +pointOrderVo.getNumber() + "-" + IdUtils.singletonSnowId());
            processOrder.setWorkType("point");
            processOrder.setWorkStartTime(item.getWorkStartTime());
            processOrder.setWorkEndTime(item.getWorkEndTime());
            processOrder.setUserId(pointOrderVo.getApplyId());
            processOrder.setDeptId(pointOrderVo.getApplyDeptId());
            processOrder.setNickName(pointOrderVo.getApplyName());
            processOrder.setDeptName(pointOrderVo.getApplyDeptName());
            processOrder.setSourceId(mainId.toString());//添加一个申请单id作为sourceId
            processOrder.setWorkTime(item.getHours()); //工序工时=加工小时
            processOrder.setWorkCost(item.getQuota()); // 工序工价 = 加工定额
            processOrder.setAssignedCost(item.getDetails().stream().map(PointOrderItemDetail::getAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
            orders.add(processOrder);

            //工单派工人员
            List<PointOrderItemDetail> details = item.getDetails();
            details.forEach(d -> {
                Long userId = d.getUserId();
                ProcessOrderUsers processOrderUsers = new ProcessOrderUsers();
                processOrderUsers.setUserId(userId);
                processOrderUsers.setNickName(d.getNickName());
                processOrderUsers.setDeptId(d.getDeptId());
                processOrderUsers.setDeptName(d.getDeptName());
                processOrderUsers.setWorkId(processOrder.getWorkId());
                processOrderUsers.setActualTimes(d.getWorkTime());
                processOrderUsers.setTimes(d.getWorkTime());
                processOrderUsers.setPrices(d.getAmount());
                processOrderUsers.setCheckTime(DateUtils.getNowDate());
                processOrderUsers.setReportTime(DateUtils.getNowDate());
                processOrderUsers.setReceiveTime(DateUtils.getNowDate());
                processOrderUsers.setStatus(0);
//                processOrderUsers.setTimes(d.getWorkTime());
                orderUsers.add(processOrderUsers);
            });
        });

        //批量保存
        if (CollUtil.isNotEmpty(orders) && CollUtil.isNotEmpty(orderUsers)) {
//            processOrderService.saveBatch(orders);
//            processOrderUsersService.saveBatch(orderUsers);
            //发送提醒消息
            senMsg(mainId, title, pointOrderVo, userName, createTime, oUserId, processInstanceId);
            return true;
        }
        return false;
    }

    @Override
    public SysUser selectBomCraftUserIdsByBomId(Long bomId) {
        return pointOrderMapper.selectBomCraftUserIdsByBomId(bomId);
    }


    private void senMsg(Long mainId, String title, PointOrderVo pointOrderVo, String userName, String createTime, String oUserId, String processInstanceId) {
        //发消息给开工令上绑定bom的工艺员
        List<Long> projectIds = pointOrderVo.getItems().stream().map(PointOrderItem::getProjectId).distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(projectIds)) return;
        List<SysUser> userIds = pointOrderMapper.selectBomCraftUserIds(projectIds);
        List<Msg> msgList = new ArrayList<>();
        if (CollUtil.isNotEmpty(userIds) && CollectionUtils.isNotEmpty(userIds.stream().filter(e -> ObjectUtils.isNotNull(e)).collect(Collectors.toList()))) {
            msgList = userIds.stream().filter(e -> ObjectUtils.isNotNull(e)).map(uId -> {
                return getMsg(mainId, title, userName, createTime, processInstanceId, uId);
            }).collect(Collectors.toList());
            Msg msg = new Msg();
            msg.setTitle(title);
            msg.setSourceId(mainId.toString());
            msg.setSourceType("point");
            msg.setContent("您收到一条新非标准定额申请单消息");
            msg.setUserId(Long.parseLong(oUserId));
            msg.setUrl(FlowableKeyEnum.flowToValues("point_t") + "?id=" + mainId.toString());
            msg.setOriginCreateDateTime(DateUtils.strToDate(createTime, DatePattern.NORM_DATETIME_PATTERN));
            msg.setCreateByName(userName);
            msg.setTaskId(null);
            msg.setProcessInstanceId(processInstanceId);
            msgList.add(msg);

        }

        List<SysUser> users = pointOrderVo.getItems().stream().map(e -> {
            SysUser user1 = new SysUser();
            user1.setUserId(e.getManagerId());
            user1.setNickName(e.getManagerName());
            return user1;
        }).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(users)) {
            for (SysUser uId : users) {
                msgList.add(getMsg(mainId, title, userName, createTime, processInstanceId, uId));
            }
        }
        if (CollectionUtils.isNotEmpty(msgList)) {
            msgService.saveBatch(msgList, true, true);
        }
    }

    @NotNull
    private static Msg getMsg(Long mainId, String title, String userName, String createTime, String processInstanceId, SysUser uId) {
        Msg msg = new Msg();
        msg.setTitle(title);
        msg.setSourceId(mainId.toString());
        msg.setSourceType("point");
        msg.setContent("您收到一条新非标准定额申请单消息");
        msg.setUserId(uId.getUserId());
        msg.setUrl(FlowableKeyEnum.flowToValues("point_t") + "?id=" + mainId.toString());
        msg.setOriginCreateDateTime(DateUtils.strToDate(createTime, DatePattern.NORM_DATETIME_PATTERN));
        msg.setCreateByName(userName);
        msg.setTaskId(null);
        msg.setProcessInstanceId(processInstanceId);
        return msg;
    }

    private void check(PointOrderVo pointOrderVo) {
        if (pointOrderVo == null) {
            throw new ServiceException("E01:根据主键未找到申请数据");
        }
        if (CollUtil.isEmpty(pointOrderVo.getItems())) {
            throw new ServiceException("E01:申请任务不存在");
        }
        pointOrderVo.getItems().forEach(i -> {
            if (CollUtil.isEmpty(i.getDetails())) {
                throw new ServiceException("E01:申请的工单未指定派工人员");
            }
        });
    }

    private void validate(PointOrderVo pointOrderVo) {
        if (pointOrderVo == null) {
            throw new ServiceException("E01:数据错误:未提交数据");
        }
        if (CollUtil.isEmpty(pointOrderVo.getItems())) {
            throw new ServiceException("E01:数据错误:未提交任务清单数据");
        }
        pointOrderVo.getItems().forEach(e -> {
            if (e.getWorkOrderDetailId() == null) {
                throw new ServiceException("E01:数据错误:未提交生产工单");
            }
        });
        pointOrderVo.getItems().forEach(p -> {
            if (CollUtil.isEmpty(p.getDetails())) {
                throw new ServiceException("E01:数据错误:未提交任务清单派工人员");
            }
        });
    }

}
